Security News
PyPI Introduces Digital Attestations to Strengthen Python Package Security
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
fast-redact
Advanced tools
The fast-redact npm package is designed for redacting sensitive information from objects without mutating the original object. It is optimized for performance and can handle various patterns and paths for redaction.
Static Redaction
Redacts specified paths from an object. In this example, the 'password' and 'ssn' fields of the 'user' object are redacted.
const redact = require('fast-redact')({ paths: ['user.password', 'user.ssn'] });
const user = { name: 'Alice', password: 's3cret', ssn: '123-45-6789' };
const safeUser = redact(user);
console.log(safeUser);
Dynamic Redaction
Allows for dynamic redaction based on the path of the property being redacted. In this example, all properties under 'user' are redacted with a '[REDACTED]' suffix.
const redact = require('fast-redact')({
paths: ['user.*'],
dynamicRedaction: {
path: (path) => path + '[REDACTED]'
}
});
const user = { name: 'Alice', password: 's3cret', ssn: '123-45-6789' };
const safeUser = redact(user);
console.log(safeUser);
Wildcard Redaction
Supports wildcard patterns to redact all matching paths. In this example, all properties of the 'user' object are redacted.
const redact = require('fast-redact')({ paths: ['user.*'] });
const user = { name: 'Alice', password: 's3cret', ssn: '123-45-6789', email: 'alice@example.com' };
const safeUser = redact(user);
console.log(safeUser);
Conditional Redaction
Allows redaction based on a condition. In this example, the 'ssn' field is redacted only if the user's age is less than 18.
const redact = require('fast-redact')({
paths: ['user.ssn'],
condition: (value, path, object) => object.user.age < 18
});
const user = { name: 'Alice', age: 17, ssn: '123-45-6789' };
const safeUser = redact(user);
console.log(safeUser);
Similar to fast-redact, redact-object is used to redact sensitive information from objects. It offers a simple API but may not be as performance-optimized as fast-redact.
While primarily a logger for Express applications, express-pino-logger uses fast-redact internally to redact sensitive information from log messages. It provides a similar redaction feature but within the context of logging.
very fast object redaction
By default, fast-redact
serializes an object with JSON.stringify
, censoring any
data at paths specified:
const fastRedact = require('fast-redact')
const fauxRequest = {
headers: {
host: 'http://example.com',
cookie: `oh oh we don't want this exposed in logs in etc.`,
referer: `if we're cool maybe we'll even redact this`,
// Note: headers often contain hyphens and require bracket notation
'X-Forwarded-For': `192.168.0.1`
}
}
const redact = fastRedact({
paths: ['headers.cookie', 'headers.referer', 'headers["X-Forwarded-For"]']
})
console.log(redact(fauxRequest))
// {"headers":{"host":"http://example.com","cookie":"[REDACTED]","referer":"[REDACTED]","X-Forwarded-For": "[REDACTED]"}}
require('fast-redact')({paths, censor, serialize}) => Function
When called without any options, or with a zero length paths
array,
fast-redact
will return JSON.stringify
or the serialize
option, if set.
paths
– Array
An array of strings describing the nested location of a key in an object.
The syntax follows that of the EcmaScript specification, that is any JavaScript
path is accepted – both bracket and dot notation is supported. For instance in
each of the following cases, the c
property will be redacted: a.b.c
,a['b'].c
,
a["b"].c
, a[``b``].c
. Since bracket notation is supported, array indices are also
supported a[0].b
would redact the b
key in the first object of the a
array.
Leading brackets are also allowed, for instance ["a"].b.c
will work.
In addition to static paths, asterisk wildcards are also supported.
When an asterisk is place in the final position it will redact all keys within the
parent object. For instance a.b.*
will redact all keys in the b
object. Similarly
for arrays a.b[*]
will redact all elements of an array (in truth it actually doesn't matter
whether b
is in an object or array in either case, both notation styles will work).
When an asterisk is in an intermediate or first position, the paths following the asterisk will be redacted for every object within the parent.
For example:
const fastRedact = require('fast-redact')
const redact = fastRedact({paths: ['*.c.d']})
const obj = {
x: {c: {d: 'hide me', e: 'leave me be'}},
y: {c: {d: 'and me', f: 'I want to live'}},
z: {c: {d: 'and also I', g: 'I want to run in a stream'}}
}
console.log(redact(obj))
// {"x":{"c":{"d":"[REDACTED]","e":"leave me be"}},"y":{"c":{"d":"[REDACTED]","f":"I want to live"}},"z":{"c":{"d":"[REDACTED]","g":"I want to run in a stream"}}}
Another example with a nested array:
const fastRedact = require('..')
const redact = fastRedact({paths: ['a[*].c.d']})
const obj = {
a: [
{c: {d: 'hide me', e: 'leave me be'}},
{c: {d: 'and me', f: 'I want to live'}},
{c: {d: 'and also I', g: 'I want to run in a stream'}}
]
}
console.log(redact(obj))
// {"a":[{"c":{"d":"[REDACTED]","e":"leave me be"}},{"c":{"d":"[REDACTED]","f":"I want to live"}},{"c":{"d":"[REDACTED]","g":"I want to run in a stream"}}]}
remove
- Boolean
- [false]
The remove
option, when set to true
will cause keys to be removed from the
serialized output.
Since the implementation exploits the fact that undefined
keys are ignored
by JSON.stringify
the remove
option may only be used when JSON.stringify
is the serializer (this is the default) – otherwise fast-redact
will throw.
If supplying a custom serializer that has the same behavior (removing keys
with undefined
values), this restriction can be bypassed by explicitly setting
the censor
to undefined
.
censor
– <Any type>
– ('[REDACTED]')
This is the value which overwrites redacted properties.
Setting censor
to undefined
will cause properties to removed as long as this is
the behavior of the serializer
– which defaults to JSON.stringify
, which does
remove undefined
properties.
Setting censor
to a function will cause fast-redact
to invoke it with the original
value. The output of the censor
function sets the redacted value.
Please note that asynchronous functions are not supported.
serialize
– Function | Boolean
– (JSON.stringify)
The serialize
option may either be a function or a boolean. If a function is supplied, this
will be used to serialize
the redacted object. It's important to understand that for
performance reasons fast-redact
mutates the original object, then serializes, then
restores the original values. So the object passed to the serializer is the exact same
object passed to the redacting function.
The serialize
option as a function example:
const fastRedact = require('fast-redact')
const redact = fastRedact({
paths: ['a'],
serialize: (o) => JSON.stringify(o, 0, 2)
})
console.log(redact({a: 1, b: 2}))
// {
// "a": "[REDACTED]",
// "b": 2
// }
For advanced usage the serialize
option can be set to false
. When serialize
is set to false
,
instead of the serialized object, the output of the redactor function will be the mutated object
itself (this is the exact same as the object passed in). In addition a restore
method is supplied
on the redactor function allowing the redacted keys to be restored with the original data.
const fastRedact = require('fast-redact')
const redact = fastRedact({
paths: ['a'],
serialize: false
})
const o = {a: 1, b: 2}
console.log(redact(o) === o) // true
console.log(o) // { a: '[REDACTED]', b: 2 }
console.log(redact.restore(o) === o) // true
console.log(o) // { a: 1, b: 2 }
strict
– Boolean
- [true]
The strict
option, when set to true
, will cause the redactor function to throw if instead
of an object it finds a primitive. When strict
is set to false
, the redactor function
will treat the primitive value as having already been redacted, and return it serialized (with
JSON.stringify
or the user's custom serialize
function), or as-is if the serialize
option
was set to false.
In order to achieve lowest cost/highest performance redaction fast-redact
creates and compiles a function (using the Function
constructor) on initialization.
It's important to distinguish this from the dangers of a runtime eval, no user input
is involved in creating the string that compiles into the function. This is as safe
as writing code normally and having it compiled by V8 in the usual way.
Thanks to changes in V8 in recent years, state can be injected into compiled functions
using bind
at very low cost (whereas bind
used to be expensive, and getting state
into a compiled function by any means was difficult without a performance penalty).
For static paths, this function simply checks that the path exists and then overwrites with the censor. Wildcard paths are processed with normal functions that iterate over the object redacting values as necessary.
It's important to note, that the original object is mutated – for performance reasons a copy is not made. See rfdc (Really Fast Deep Clone) for the fastest known way to clone – it's not nearly close enough in speed to editing the original object, serializing and then restoring values.
A restore
function is also created and compiled to put the original state back on
to the object after redaction. This means that in the default usage case, the operation
is essentially atomic - the object is mutated, serialized and restored internally which
avoids any state management issues.
As mentioned in approach, the paths
array input is dynamically compiled into a function
at initialization time. While the paths
array is vigourously tested for any developer
errors, it's strongly recommended against allowing user input to directly supply any
paths to redact. It can't be guaranteed that allowing user input for paths
couldn't
feasibly expose an attack vector.
The fastest known predecessor to fast-redact
is the non-generic pino-noir
library (which was also written by myself).
In the direct calling case, fast-redact
is ~30x faster than pino-noir
, however a more realistic
comparison is overhead on JSON.stringify
.
For a static redaction case (no wildcards) pino-noir
adds ~25% overhead on top of JSON.stringify
whereas fast-redact
adds ~1% overhead.
In the basic last-position wildcard case,fast-redact
is ~12% faster than pino-noir
.
The pino-noir
module does not support intermediate wildcards, but fast-redact
does,
the cost of an intermediate wildcard that results in two keys over two nested objects
being redacted is about 25% overhead on JSON.stringify
. The cost of an intermediate
wildcard that results in four keys across two objects being redacted is about 55% overhead
on JSON.stringify
and ~50% more expensive that explicitly declaring the keys.
npm run bench
benchNoirV2*500: 59.108ms
benchFastRedact*500: 2.483ms
benchFastRedactRestore*500: 10.904ms
benchNoirV2Wild*500: 91.399ms
benchFastRedactWild*500: 21.200ms
benchFastRedactWildRestore*500: 27.304ms
benchFastRedactIntermediateWild*500: 92.304ms
benchFastRedactIntermediateWildRestore*500: 107.047ms
benchJSONStringify*500: 210.573ms
benchNoirV2Serialize*500: 281.148ms
benchFastRedactSerialize*500: 215.845ms
benchNoirV2WildSerialize*500: 281.168ms
benchFastRedactWildSerialize*500: 247.140ms
benchFastRedactIntermediateWildSerialize*500: 333.722ms
benchFastRedactIntermediateWildMatchWildOutcomeSerialize*500: 463.667ms
benchFastRedactStaticMatchWildOutcomeSerialize*500: 239.293ms
npm test
224 passing (499.544ms)
npm run cov
-----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
fast-redact | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
fast-redact/lib | 100 | 100 | 100 | 100 | |
modifiers.js | 100 | 100 | 100 | 100 | |
parse.js | 100 | 100 | 100 | 100 | |
redactor.js | 100 | 100 | 100 | 100 | |
restorer.js | 100 | 100 | 100 | 100 | |
rx.js | 100 | 100 | 100 | 100 | |
state.js | 100 | 100 | 100 | 100 | |
validator.js | 100 | 100 | 100 | 100 | |
-----------------|----------|----------|----------|----------|-------------------|
MIT
Sponsored by nearForm
FAQs
very fast object redaction
The npm package fast-redact receives a total of 3,929,713 weekly downloads. As such, fast-redact popularity was classified as popular.
We found that fast-redact demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.